package com.leenmvc.core.dao.communal;

import com.leenmvc.core.annotation.TransactionMulti;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 自定义注解实现事务， 切面类
 */
@Aspect
@Component
public class AopTransactionMulti {

    // && execution(* com.ruien.core.security.service.core.*.*(..))
    @Pointcut("execution(* com.ruien.iot.service..*.*(..)) || execution(* com.ruien.core.security.service.core.*.*(..))")
    private void pointcut() {}

    // 使用异常通知进行 回滚事务
    @AfterThrowing("pointcut()")
    public void afterThrowing() {
        // 获取当前事务进行回滚
        TransactionManager.rollBack();
    }

    // 环绕通知 在方法之前和之后处理事情
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        Object result = null;
        if(TransactionManager.getTrans() == 0) { // 如果不在事务当中那么判断该方法是不是事务方法，如果是那么开启事务
            TransactionMulti beginTransaction = getMethodSelfAnnotation(pjp);
            begin(beginTransaction);
            result = pjp.proceed();
            commit(beginTransaction);
        } else if (TransactionManager.getTrans() == 1) { // 如果已经处在事务中，那么直接执行命中的方法，不在重新开启事务
            result = pjp.proceed();
        }
        return result;
    }

    /**
     * 开启事务
     *
     * @param selfAnnotation
     */
    private void begin(TransactionMulti selfAnnotation) {
        if (selfAnnotation != null) {
            TransactionManager.setTrans(1);
        }
    }

    /**
     * 提交事务
     * @param selfAnnotation
     */
    private void commit(TransactionMulti selfAnnotation) {
        if (selfAnnotation != null) {
            TransactionManager.commit();
            TransactionManager.setTrans(0);
        }
    }

    // 获取方法上是否存在事务注解
    private TransactionMulti getMethodSelfAnnotation(ProceedingJoinPoint pjp)
            throws NoSuchMethodException, SecurityException {
        String methodName = pjp.getSignature().getName();
        //	 获取目标对象
        Class<?> classTarget = pjp.getTarget().getClass();
        //	 获取目标对象类型
        Class<?>[] par = ((MethodSignature) pjp.getSignature()).getParameterTypes();
        //	 获取目标对象方法
        Method objMethod = classTarget.getMethod(methodName, par);
        TransactionMulti selfAnnotation = objMethod.getDeclaredAnnotation(TransactionMulti.class);
        return selfAnnotation;
    }

}